package userSession

import (
	"context"
	"fmt"
	"gitee.com/kaylee595/gkaylee/kerr"
	proxyPool "gitee.com/kaylee595/proxy-pool"
	"github.com/samber/lo"
	"net/url"
	"time"
)

type UsernameHandler func(username string, expireDuration time.Duration) (string, error)

type source struct {
	scheme          string
	host            string
	username        string
	password        string
	usernameHandler UsernameHandler
	expireDuration  time.Duration
	maxUses         uint64
	count           uint64
}

// New 有些隧道代理支持通过username来固定代理, 本函数皆在实现 proxyPool.Source.
// 默认情况下, username将通过 NewReplaceRandomSession(26, lo.NumbersCharset) 的规则来修改username, 修改请用 WithUsernameHandler.
// 当 Fetch 方法被调用时, 默认会生成20个节点, 更改请使用 WithCount.
// 每个代理将被标记为的有效期为5分钟, 修改请使用 WithExpire.
func New(scheme, host, username, password string, options ...Option) proxyPool.Source {
	s := &source{
		scheme:          scheme,
		host:            host,
		username:        username,
		password:        password,
		usernameHandler: NewReplaceRandomSession(26, lo.NumbersCharset),
		expireDuration:  5 * time.Minute,
		count:           20,
	}
	for _, opt := range options {
		opt(s)
	}
	return s
}

func (s *source) Fetch(_ context.Context) ([]proxyPool.Node, error) {
	rets := make([]proxyPool.Node, 0, s.count)
	for range s.count {
		username, err := s.usernameHandler(s.username, s.expireDuration)
		if err != nil {
			return nil, kerr.WrapTraceStack(fmt.Errorf("%w, username: %s", err, username))
		}
		proxyUrl := &url.URL{
			Scheme: s.scheme,
			Host:   s.host,
			User:   url.UserPassword(username, s.password),
		}
		if s.maxUses > 0 && s.expireDuration > 0 {
			rets = append(rets, proxyPool.NewNodeWithExpirationDurationMaxUses(proxyUrl, s.expireDuration, s.maxUses))
		} else if s.expireDuration > 0 {
			rets = append(rets, proxyPool.NewNodeWithExpirationDuration(proxyUrl, s.expireDuration))
		} else if s.maxUses > 0 {
			rets = append(rets, proxyPool.NewNodeWithMaxUses(proxyUrl, s.maxUses))
		}
	}
	return rets, nil
}
